/**
 * @file GDLR.h
 * @author Goldfish1295
 * @brief Solving Multiple Linear Regression with Gradient Descent.
 * @attention Using this header, you must define you own ExceptionHandler() function
 * @version v1.0
 */
#ifndef RENESAS_GDLR_GDLR_H_
#define RENESAS_GDLR_GDLR_H_

#include <stdlib.h>
/*
#include <stdio.h>
*/

/**
 * @brief Exception handling function, waiting for user to define
 */
void ExceptionHandler();

/**
 * @brief Vector structure
 */
struct vector
{
    int dim;     ///< Dimension
    double *val; ///< Values
};

/**
 * @brief required params to begin a GDLR
 * @param decent_origin_theta Initial coefficient of gradient descent
 * @param decent_origin_epsilon Initial deviation of gradient descent
 * @param learning_rate Learning step size
 * @param sensitivity The rate of decline in learning rate, recommended to be around 0.8
 * @param iter_limit Maximum number of iterations
 * @param triger Reminder of decreased learning rate
 * @param patience Optimize patience and describe the stopping goal of the early stop algorithm
 * @param target_accuracy The accuracy of mean square error, recommended to be lower than 1e-5
*/
typedef struct {
    struct vector *decent_origin_theta;
    double *decent_origin_epsilon;
    double learning_rate;
    double sensitivity;
    double iter_limit;
    int triger;
    int patience;
    double target_accuracy;
}GDLR_Param;

void VectorAdd(struct vector a, struct vector b, struct vector *ret);
void VectorMinus(struct vector a, struct vector b, struct vector *ret);
void VectorDotProduct(struct vector a, struct vector b, double *ret);

double MeanSquaredError(struct vector *x, double *y, int *train_size, struct vector *theta, double *epsilon);
double Predict(struct vector *x, struct vector *theta, double *epsilon);

void StepGradientDescent(struct vector *x, double *y, int *train_size, struct vector *current_theta, double *current_epsilon, double learning_rate, struct vector *ret_theta, double *ret_epsilon);
void LinearRegression(struct vector *x, double *y, int train_size,
                      GDLR_Param params,
                      int *ret_iteration, double *ret_loss, struct vector *ret_theta, double *ret_epsilon);

#endif